import G6 from '@antv/g6'
import {
  pureColor,
  nodePadding,
  nodeFontSize,
  nodeBorderRadius,
  collapseGap,
  collapseRadius,
  circleRadius,
  circleGap,
  arrowGap,
} from './graphStyle'

export default function registerFn() {
  // root-node
  G6.registerNode(
    'root-node',
    {
      jsx(cfg) {
        const { _wrapWidth, _wrapHeight } = cfg
        // prettier-ignore
        return `
        <group>
          <rect style={{ width: ${_wrapWidth}, height: ${_wrapHeight}, fill: ${pureColor.rootBg}, radius: ${nodeBorderRadius} }} keyshape>
            <text style={{ fontSize: ${nodeFontSize}, fill: #fff, marginLeft: ${nodePadding[0]}, marginTop: ${nodePadding[1]}} }}>${cfg.text}</text>
          </rect>
        </group>
        `
      },
      getAnchorPoints() {
        return [
          [0, 0.5],
          [1, 0.5],
        ]
      },
    },
    'single-node'
  )

  // relation-node
  G6.registerNode('relation-node', {
    addWrapper(cfg, group) {
      const { _wrapWidth, _wrapHeight } = cfg
      return group.addShape('rect', {
        attrs: {
          x: 0,
          y: 0,
          width: _wrapWidth,
          height: _wrapHeight,
        },
      })
    },
    addLabel(cfg, group) {
      const { _direction, children } = cfg
      let x = 0
      if (_direction === 'left') {
        x = children?.length ? collapseRadius * 2 + collapseGap : 0
      } else {
        x = circleRadius * 2 + circleGap
      }
      x += nodePadding[1]
      return group.addShape('text', {
        attrs: {
          x,
          y: nodeFontSize + nodePadding[0],
          text: cfg.text,
          fontSize: nodeFontSize,
          fill: '#000',
        },
      })
    },
    addPoint(cfg, group) {
      const { _wrapWidth, _wrapHeight, _direction, mainColor } = cfg
      return group.addShape('circle', {
        attrs: {
          x: _direction === 'left' ? _wrapWidth - circleRadius : circleRadius,
          y: _wrapHeight / 2,
          r: circleRadius,
          fill: mainColor,
        },
      })
    },
    addMarker(cfg, group) {
      const { _wrapWidth, _wrapHeight, _direction } = cfg
      return group.addShape('marker', {
        attrs: {
          x: _direction === 'left' ? collapseRadius : _wrapWidth - circleRadius,
          y: _wrapHeight / 2,
          r: collapseRadius,
          symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
          stroke: pureColor.collapseColor,
          lineWidth: 1,
          cursor: 'pointer',
        },
        name: 'collapse-icon',
      })
    },
    draw(cfg, group) {
      const keyShape = this.addWrapper(cfg, group)
      // 添加文本
      this.addLabel(cfg, group)
      this.addPoint(cfg, group)

      // 添加marker
      cfg?.children?.length > 0 && this.addMarker(cfg, group)

      return keyShape
    },
    update(cfg, item) {
      const group = item.getContainer()
      const icon = group.find((e) => {
        return e.get('name') === 'collapse-icon'
      })
      icon?.attr(
        'symbol',
        cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse
      )
    },
    getAnchorPoints() {
      return [
        [0, 0.5],
        [1, 0.5],
      ]
    },
  })

  // entity-node
  G6.registerNode('entity-node', {
    addWrapper(cfg, group) {
      const { _wrapWidth, _wrapHeight, mainColor } = cfg
      return group.addShape('rect', {
        attrs: {
          x: 0,
          y: 0,
          width: _wrapWidth,
          height: _wrapHeight,
          radius: nodeBorderRadius,
          stroke: mainColor,
          fill: 'transparent',
          cursor: 'pointer',
        },
      })
    },
    addLabel(cfg, group) {
      const { _direction, children } = cfg
      let x = 0
      if (_direction === 'left') {
        x = children?.length ? collapseRadius * 2 + collapseGap : 0
      } else {
        x = 0
      }
      x += nodePadding[0]
      return group.addShape('text', {
        attrs: {
          x,
          y: nodeFontSize + nodePadding[1],
          text: cfg.text,
          fontSize: nodeFontSize,
          fill: '#000',
          cursor: 'pointer',
        },
      })
    },
    addSubText(cfg, group) {
      const { _direction, children, _textSize } = cfg
      let x = 0
      if (_direction === 'left') {
        x = children?.length ? collapseRadius * 2 + collapseGap : 0
      } else {
        x = 0
      }
      x += nodePadding[0] + _textSize[0]
      return group.addShape('text', {
        attrs: {
          x,
          y: nodeFontSize + nodePadding[1],
          text: cfg.subText,
          fontSize: nodeFontSize,
          fill: pureColor.subText,
          cursor: 'pointer',
        },
      })
    },
    addMarker(cfg, group) {
      const { _wrapWidth, _wrapHeight, _direction } = cfg
      return group.addShape('marker', {
        attrs: {
          x:
            _direction === 'left'
              ? nodePadding[0] + collapseRadius
              : _wrapWidth - nodePadding[0] - collapseRadius,
          y: _wrapHeight / 2,
          r: collapseRadius,
          symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
          stroke: pureColor.collapseColor,
          lineWidth: 1,
          cursor: 'pointer',
        },
        name: 'collapse-icon',
      })
    },
    addPoint(cfg, group) {
      const { _wrapWidth } = cfg
      return group.addShape('circle', {
        attrs: {
          x: _wrapWidth,
          y: 0,
          fill: '#F0667F',
          stroke: '#fff',
          r: 4,
        },
      })
    },
    draw(cfg, group) {
      const keyShape = this.addWrapper(cfg, group)
      // 添加文本
      this.addLabel(cfg, group)

      // 子文案
      cfg.subText && this.addSubText(cfg, group)

      // 添加marker
      cfg?.children?.length > 0 && this.addMarker(cfg, group)

      // 风险图标
      cfg?.hasPoint && this.addPoint(cfg, group)

      return keyShape
    },
    update(cfg, item) {
      const group = item.getContainer()
      const icon = group.find((e) => {
        return e.get('name') === 'collapse-icon'
      })
      icon?.attr(
        'symbol',
        cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse
      )
    },
    getAnchorPoints() {
      return [
        [0, 0.5],
        [1, 0.5],
      ]
    },
  })

  // more-node
  G6.registerNode('more-node', {
    addWrapper(cfg, group) {
      const { _wrapWidth, _wrapHeight } = cfg

      return group.addShape('rect', {
        attrs: {
          x: 0,
          y: 0,
          width: _wrapWidth,
          height: _wrapHeight,
          radius: nodeBorderRadius,
          fill: '#fff',
        },
      })
    },
    addLabel(cfg, group) {
      const { _direction } = cfg
      let x = 0
      if (_direction === 'left') {
        x = collapseRadius * 2 + collapseGap
      } else {
        x = 0
      }
      x += nodePadding[1]
      return group.addShape('text', {
        attrs: {
          x,
          y: nodeFontSize + nodePadding[1],
          text: cfg.text,
          fontSize: nodeFontSize,
          fill: '#000',
        },
      })
    },
    addSubText(cfg, group) {
      const { _direction, _textSize } = cfg
      let x = 0
      if (_direction === 'left') {
        x = collapseRadius * 2 + collapseGap
      } else {
        x = 0
      }
      x += nodePadding[0] + _textSize[0]
      return group.addShape('text', {
        attrs: {
          x,
          y: nodeFontSize + nodePadding[1],
          text: cfg.subText,
          fontSize: nodeFontSize,
          fill: pureColor.subText,
        },
      })
    },
    addMarker(cfg, group) {
      const { _wrapWidth, _wrapHeight, _direction } = cfg
      return group.addShape('marker', {
        attrs: {
          x:
            _direction === 'left'
              ? nodePadding[0] + collapseRadius
              : _wrapWidth - nodePadding[0] - collapseRadius,
          y: _wrapHeight / 2,
          r: collapseRadius,
          symbol: G6.Marker.expand,
          stroke: pureColor.collapseColor,
          lineWidth: 1,
        },
        name: 'collapse-icon',
      })
    },
    draw(cfg, group) {
      const keyShape = this.addWrapper(cfg, group)
      // 添加文本
      this.addLabel(cfg, group)

      // 子文案
      cfg.subText && this.addSubText(cfg, group)

      // 添加marker
      this.addMarker(cfg, group)

      return keyShape
    },
    getAnchorPoints() {
      return [
        [0, 0.5],
        [1, 0.5],
      ]
    },
  })

  // 折线边
  G6.registerEdge('new-line', {
    addLine(cfg, group) {
      const { startPoint, endPoint } = cfg
      const radius = 6

      let path = null
      if (Math.abs(startPoint.y - endPoint.y) < radius) {
        path = [
          ['M', startPoint.x, startPoint.y],
          ['L', endPoint.x, endPoint.y],
        ]
      } else {
        // 中间点x坐标
        const midX = (endPoint.x + startPoint.x) / 2
        // 是否朝下
        const isDown = endPoint.y > startPoint.y

        path = [
          ['M', startPoint.x, startPoint.y],
          ['L', midX, startPoint.y],
          ['L', midX, isDown ? endPoint.y - radius : endPoint.y + radius],
          [
            'Q',
            midX,
            endPoint.y,
            midX >= 0 ? midX + radius : midX - radius,
            endPoint.y,
          ],
          ['L', endPoint.x, endPoint.y],
        ]
      }

      return group.addShape('path', {
        attrs: {
          path,
          stroke: pureColor.edge,
          lineWidth: 1,
          startArrow: cfg.style.startArrow,
        },
      })
    },
    addArrow(cfg, group) {
      const { endPoint, targetNode } = cfg
      const { x, y } = endPoint
      // _direction为transformData加入的数据，表示节点在左边还是右边
      const { arrow, _direction } = targetNode.getModel()
      let path = null
      if (_direction === 'left') {
        if (arrow === 'in') {
          const startX = x + arrowGap
          path = [
            ['M', startX, y],
            ['L', startX + 10, y + 4],
            ['L', startX + 10, y - 4],
          ]
        } else {
          const startX = x + arrowGap + 10
          path = [
            ['M', startX, y],
            ['L', startX - 10, y + 4],
            ['L', startX - 10, y - 4],
          ]
        }
      } else {
        if (arrow === 'in') {
          const startX = x - arrowGap
          path = [
            ['M', startX, y],
            ['L', startX - 10, y + 4],
            ['L', startX - 10, y - 4],
          ]
        } else {
          const startX = x - arrowGap - 10
          path = [
            ['M', startX, y],
            ['L', startX + 10, y + 4],
            ['L', startX + 10, y - 4],
          ]
        }
      }
      return group.addShape('path', {
        attrs: {
          path,
          fill: pureColor.arrow,
        },
      })
    },
    draw(cfg, group) {
      const { targetNode } = cfg
      const keyShape = this.addLine(cfg, group)

      targetNode?.getModel()?.arrow && this.addArrow(cfg, group)
      return keyShape
    },
  })
}
